/**
 * 装饰器
*/
import { ModelMeta, ModelPropertyMeta, PathMeta, OperationMeta, getModelMeta, getPathMeta, ParamMeta, getOperationMeta, getParamMeta, InValues } from './Meta';
import Swagger from './index'
import { Router, RequestHandler } from 'express';
import { DataFormat, HttpMethod, Controller, Get, Post, Put, Delete, CustomGet, CustomPost, CustomPut, CustomDelete, Query, Body, QueryParam, BodyParam, ParamsParam } from '../router'
import { DataType } from './DataType'

/**
 * 实体类
*/
export function ApiModel(options: ModelMeta) {
  return function(constructor: Function) {
    const modelMeta = getModelMeta(constructor)
    modelMeta.name = options.name
    modelMeta.description = options.description
    if (typeof options.isCreateTag === 'boolean') {
      modelMeta.isCreateTag = options.isCreateTag
    }

    if (typeof options.isCreateModel === 'boolean') {
      modelMeta.isCreateModel = options.isCreateModel
    }

    Swagger.ModelMetas.push(modelMeta)
  }
}

/**
 * 实体类属性
*/
export function ApiModelProperty(options: ModelPropertyMeta) {
  return function(target: Object, propertyKey: string) {
    const modelMeta = getModelMeta(target.constructor)
    if (!options.property) {
      options.property = propertyKey
    }

    modelMeta.modelPropertyMetaList.push(options)
  }
}

/**
 * 接口路径
*/
export function ApiController(options: PathMeta, ...midwares: Array<Router | RequestHandler>) {
  if (!options.path.startsWith('/')) {
    throw new Error('请输入 / 开头的路径')
  }
  return function(constructor: Function) {
    // 调用路由功能
    Controller(options.path, ...midwares)(constructor)

    const pathMeta = getPathMeta(constructor)
    pathMeta.path = options.path
    pathMeta.tags = options.tags || []

    Swagger.PathMetas.push(pathMeta)
  }
}

/**
 * 接口方法
*/
function ApiOperationBuilder(httpMethod: HttpMethod, RouterMethod: typeof Get) {
  return function(options: OperationMeta, ...midwares: Array<Router | RequestHandler>) {
    if (!options.path.startsWith('/')) {
      throw new Error('请输入 / 开头的路径')
    }
    return function(target: Object, methodName: string) {
      // 默认解析成 json
      options.dataFormat = options.dataFormat || DataFormat.JSON

      // 调用路由功能
      RouterMethod(options.path, options.dataFormat, ...midwares)(target, methodName)

      const operationMeta = getOperationMeta(target, methodName)

      operationMeta.path = options.path
      operationMeta.summary = options.summary
      operationMeta.description = options.description
      operationMeta.httpMethod = httpMethod
      operationMeta.description = options.description || ''
      operationMeta.dataFormat = options.dataFormat

      if (options.parameterList) {
        operationMeta.parameterList = operationMeta.parameterList.concat(options.parameterList)
      }

      if (options.parameterModel) {
        operationMeta.parameterModel = options.parameterModel
      }

      if (options.responseList) {
        operationMeta.responseList = options.responseList
      }

      if (options.responseModel) {
        operationMeta.responseModel = options.responseModel
      }
    }
  }
}

export const ApiGet = ApiOperationBuilder('get', Get)
export const ApiPost = ApiOperationBuilder('post', Post)
export const ApiPut = ApiOperationBuilder('put', Put)
export const ApiDelete = ApiOperationBuilder('delete', Delete)

export const ApiCustomGet = ApiOperationBuilder('get', CustomGet)
export const ApiCustomPost = ApiOperationBuilder('post', CustomPost)
export const ApiCustomPut = ApiOperationBuilder('put', CustomPut)
export const ApiCustomDelete = ApiOperationBuilder('delete', CustomDelete)

/**
 * 接口参数
*/
function ApiModelParamBuilder(ParamMethod: typeof Query) {
  return function(options?: ParamMeta) {
    return function (target: Object, methodName: string, paramIndex: number) {
      // 调用路由功能
      ParamMethod(target, methodName, paramIndex)

      const operationMeta = getOperationMeta(target, methodName)

      // model 参数默认 type object
      if (!options || !options.type) {
        options = Object.assign(options || {}, { type: DataType.Object })
      }
      const paramMeta = getParamMeta(options)

      operationMeta.parameterModel = paramMeta
    }
  }
}

function ApiSingleParamBuilder(ParamMethod: typeof QueryParam, inValue?: InValues) {
  return function(options?: ParamMeta) {
    if (!options.name) {
      throw new Error('请输入参数名称')
    }
    return function (target: Object, methodName: string, paramIndex: number) {
      // 调用路由功能
      ParamMethod(options.name)(target, methodName, paramIndex)

      const operationMeta = getOperationMeta(target, methodName)

      // 单个 参数默认 type string
      const paramMeta = getParamMeta(options)

      if (inValue) {
        paramMeta.in = inValue
      }

      operationMeta.parameterList.push(paramMeta)
    }
  }
}

export const ApiQuery = ApiModelParamBuilder(Query)
export const ApiBody = ApiModelParamBuilder(Body)

export const ApiQueryParam = ApiSingleParamBuilder(QueryParam, 'query')
export const ApiBodyParam = ApiSingleParamBuilder(BodyParam, 'formData')
export const ApiParamsParam = ApiSingleParamBuilder(ParamsParam, 'path')

